/**
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 *   
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 */
package org.jiopi.ibean.kernel.context;


import java.util.HashSet;
import java.util.Map;
import org.junit.Test;
import org.junit.BeforeClass;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertNotSame;

import org.jiopi.ibean.example.blueprint.testredefine.RedefineInterface;
import org.jiopi.ibean.kernel.util.ObjectAccessor;
import org.jiopi.framework.ControlPanel;
import org.jiopi.framework.FrameworkInitializer;
import org.jiopi.framework.CentralConsole;
import org.jiopi.framework.ModuleConsole;
import star.trek.voyager.blueprint.car.Car;
import org.jiopi.blueprint.mailsender.Mail;
import org.jiopi.blueprint.mailsender.MailSender;
import org.jiopi.blueprint.mailsender.SendMailException;

/**
 * Test for ModuleConsoleImpl
 *
 */
public class ModuleConsoleImplTestCase {
	
	@BeforeClass public static void init(){
		FrameworkInitializer.initialize();
	}
	@Test public void splitRegisterName_Right() {
		{
			String registerName = null;
			String[] names = ObjectAccessor.Accessible.strictMethod(ModuleConsoleImpl.class, "splitRegisterName",String[].class, new Object[] { String.class },registerName);
			assertNull(names);
		}
		{
			String registerName = "org.jiopi.ibean.RegisterName.test";
			String[] names = ObjectAccessor.Accessible.strictMethod(ModuleConsoleImpl.class, "splitRegisterName",String[].class, new Object[] { String.class },registerName);
			assertArrayEquals(new String[] {"org.jiopi.ibean.RegisterName", "test" },names);
		}
		{
			String registerName = "RegisterName.test";
			String[] names = ObjectAccessor.Accessible.strictMethod(ModuleConsoleImpl.class, "splitRegisterName",String[].class, new Object[] { String.class },registerName);
			assertArrayEquals(new String[] {"RegisterName", "test" },names);
		}
	}
	@Test public void splitRegisterName_Wrong(){
		{
			String registerName="wrong";
			String[] names = ObjectAccessor.Accessible.strictMethod(ModuleConsoleImpl.class, "splitRegisterName", String[].class, new Object[]{String.class}, registerName);
			assertNull(names);
		}
		{
			String registerName=".wrong";
			String[] names = ObjectAccessor.Accessible.strictMethod(ModuleConsoleImpl.class, "splitRegisterName", String[].class, new Object[]{String.class}, registerName);
			assertNull(names);
		}
		{
			String registerName="wrong.";
			String[] names = ObjectAccessor.Accessible.strictMethod(ModuleConsoleImpl.class, "splitRegisterName", String[].class, new Object[]{String.class}, registerName);
			assertNull(names);
		}
	}
	@Test public void operate_Right(){
		ModuleConsole testpojo = CentralConsole.accessModuleConsole("jiopi.ibean.testpojo");
		{
			String r = testpojo.operate("org.jiopi.ibean.example.module.testpojo.SimpleCall.simpleStaticCall", String.class);
			assertEquals("simpleStaticCall",r);
		}
		{
			String r = testpojo.operate("org.jiopi.ibean.example.module.testpojo.SimpleCall.simpleStaticCallWithArg", String.class,"arg");
			assertEquals("simpleStaticCallWithArg arg",r);
		}
	}
	@Test public void operateStrict_Right(){
		ModuleConsole testpojo = CentralConsole.accessModuleConsole("jiopi.ibean.testpojo");
		{
			String r = testpojo.operateStrict("org.jiopi.ibean.example.module.testpojo.SimpleCall.simpleStaticCall", String.class,new Object[]{});
			assertEquals("simpleStaticCall",r);
		}
		{
			String r = testpojo.operateStrict("org.jiopi.ibean.example.module.testpojo.SimpleCall.simpleStaticCallWithArg", String.class,new Object[]{String.class},"arg");
			assertEquals("simpleStaticCallWithArg arg",r);
		}
	}
	@Test public void staticVariable_Right(){
		ModuleConsole testpojo = CentralConsole.accessModuleConsole("jiopi.ibean.testpojo");
		{
			String r = testpojo.staticVariable("org.jiopi.ibean.example.module.testpojo.SimpleInterface.varString", String.class);
			assertEquals("varString",r);
		}
	}
	
	/**
	 * Module Console Test of JIOPi version 0.2
	 */
	@Test public void test_JIOPi_0_2(){
		ModuleConsole testModule = CentralConsole.accessModuleConsole("jiopi.ibean.testmodule", "0.2.0.0");
		{// test of AbstractClassControlPanel
			String abstractClassStaticString = testModule.staticVariable("org.jiopi.ibean.example.blueprint.testblueprint.AbstractClassControlPanel.abstractClassStaticString", String.class);
			assertEquals("abstractClassStaticString",abstractClassStaticString);
			abstractClassStaticString = testModule.staticVariable("AbstractClassControlPanel.abstractClassStaticString", String.class);
			assertEquals("abstractClassStaticString",abstractClassStaticString);
			
			
			org.jiopi.ibean.example.blueprint.testblueprint.AbstractClassControlPanel acp = testModule.accessControlPanel("AbstractClassControlPanel", org.jiopi.ibean.example.blueprint.testblueprint.AbstractClassControlPanel.class);
			assertEquals("abstractClassStaticString",acp.abstractClassStaticString);
			assertEquals("abstractClassMethod in InterfaceAndAbstractClassControlPanelImpl",acp.abstractClassMethod());
			
			org.jiopi.ibean.example.blueprint.testblueprint.AbstractClassControlPanel acpMy = testModule.accessControlPanel("AbstractClassControlPanel", org.jiopi.ibean.example.blueprint.testblueprint.AbstractClassControlPanel.class,"my");
			assertEquals("abstractClassStaticString",acpMy.abstractClassStaticString);
			assertEquals("abstractClassMethod in InterfaceAndAbstractClassControlPanelImpl my",acpMy.abstractClassMethod());
			
			ControlPanel cp = testModule.accessControlPanel("AbstractClassControlPanel", ControlPanel.class);
			assertEquals("abstractClassStaticString",cp.variable("abstractClassStaticString", String.class));
			assertEquals("abstractClassMethod in InterfaceAndAbstractClassControlPanelImpl",cp.operate("abstractClassMethod", String.class));
			
			ControlPanel cpMy = testModule.accessControlPanel("AbstractClassControlPanel", ControlPanel.class,"my");
			assertEquals("abstractClassStaticString",cpMy.variable("abstractClassStaticString", String.class));
			assertEquals("abstractClassMethod in InterfaceAndAbstractClassControlPanelImpl my",cpMy.operate("abstractClassMethod", String.class));
		}
		{//test of ClassControlPanel
			String classStaticString = testModule.staticVariable("org.jiopi.ibean.example.blueprint.testblueprint.ClassControlPanel.classStaticString", String.class);
			assertEquals("classStaticString",classStaticString);
			classStaticString = testModule.staticVariable("classStaticString", String.class);
			assertEquals("classStaticString",classStaticString);
			
			String classMethod = testModule.operate("classMethod", String.class);
			assertEquals("classMethod in NewInterfaceAndClassControlPanelImpltrue",classMethod);
		}
		{//InterfaceControlPanel
			String interfaceStaticString = testModule.staticVariable("interfaceStaticString", String.class);
			assertEquals("interfaceStaticString",interfaceStaticString);

			String interfaceMethod = testModule.operate("interfaceMethod", String.class);
			assertEquals("interfaceMethod in InterfaceAndAbstractClassControlPanelImpl",interfaceMethod);
		}
		{//NewInterfaceControlPanel
			String newInterfaceMethod = testModule.operate("newInterfaceMethod", String.class);
			assertEquals("newInterfaceMethod in NewInterfaceAndClassControlPanelImpltrue",newInterfaceMethod);
		}
		{//singleton test
			org.jiopi.ibean.example.blueprint.testblueprint.NewInterfaceControlPanel ncp = testModule.accessControlPanel("NewInterfaceControlPanel", org.jiopi.ibean.example.blueprint.testblueprint.NewInterfaceControlPanel.class);
			org.jiopi.ibean.example.blueprint.testblueprint.ClassControlPanel ccp = testModule.accessControlPanel("ClassControlPanel", org.jiopi.ibean.example.blueprint.testblueprint.ClassControlPanel.class);
			assertSame(ncp,ccp);
		}
		{//prototype test
			org.jiopi.ibean.example.blueprint.testblueprint.AbstractClassControlPanel acp = testModule.accessControlPanel("AbstractClassControlPanel", org.jiopi.ibean.example.blueprint.testblueprint.AbstractClassControlPanel.class);
			org.jiopi.ibean.example.blueprint.testblueprint.AbstractClassControlPanel acp2 = testModule.accessControlPanel("AbstractClassControlPanel", org.jiopi.ibean.example.blueprint.testblueprint.AbstractClassControlPanel.class);
			assertNotSame(acp,acp2);
		}
	}
	
	/**
	 * Module Console Test of JIOPi version 0.3
	 */
	@Test public void test_JIOPi_0_3(){
		ModuleConsole car = CentralConsole.accessModuleConsole("voyager.benz.car_sls_amg", "0.1.0.0");
		{//new default car
			
			//Car check
			Car benzSLS = car.accessControlPanel(Car.class.getName(), Car.class);
			
//			Object logger = ObjectAccessor.Accessible.variable(benzSLS, "logger", null);
//			System.out.println(logger.getClass().getClassLoader());
			
			//Car benzSLS = car.accessControlPanel("voyager.car", Car.class);
			assertEquals("star.trek.voyager.module.benz.car_sls_amg.BenzSlsAmg-0.1.0.0",benzSLS.toString());
			Object engine = ObjectAccessor.Accessible.variable(benzSLS, "engine", null);
			assertEquals("star.trek.voyager.module.benz.engine_v8.EngineV8-0.1.0.0",engine.toString());
			
			//Engine check
			Object statusCheckerControlPanel = ObjectAccessor.Accessible.variable(engine, "statusChecker", null);
			Object statusChecker = ObjectAccessor.Accessible.variable(statusCheckerControlPanel,"wrapped",null);
			assertEquals("star.trek.voyager.module.pojo.status_checker.StatusChecker-0.1.0.0",statusChecker.toString());
			Object statusOutput = ObjectAccessor.Accessible.variable(engine, "statusOutput", null);
			assertEquals("star.trek.voyager.module.benz.car_sls_amg.BenzSlsAmg-0.1.0.0",statusOutput.toString());
			Object engineSocket = ObjectAccessor.Accessible.variable(engine, "engineSocket", null);
			assertEquals("star.trek.voyager.module.common.etasocket_common.CommonETASocket-0.1.0.0",engineSocket.toString());
			Object tempEngineSocket = ObjectAccessor.Accessible.variable(engine, "tempEngineSocket", null);
			assertNull(tempEngineSocket);
			
			//CommonETASocket check
			Object statusAbleModule = ObjectAccessor.Accessible.variable(engineSocket, "statusAbleModule", null);
			assertEquals("star.trek.voyager.module.benz.axletree_amg.AMGAxletree-0.1.0.0",statusAbleModule.toString());
			Object axletreeSocket = ObjectAccessor.Accessible.variable(engineSocket, "axletreeSocket", null);
			assertEquals("star.trek.voyager.module.benz.axletree_amg.AMGAxletree-0.1.0.0",axletreeSocket.toString());
			
			//AMGAxletree check
			Object[] wheels = ObjectAccessor.Accessible.variable(axletreeSocket, "wheels", null);
			int wheelNum = ObjectAccessor.Accessible.variable(axletreeSocket, "wheelNum", int.class);
			HashSet<Object> wheelSet = new HashSet<Object>();
			for(Object wheel:wheels){
				if(wheel!=null)wheelSet.add(wheel);
			}
			assertEquals(wheelNum,wheelSet.size());
			assertEquals(4,wheelNum);

		}
		{//car with enginev9 and two wheels
			Car benzSLS = car.accessControlPanel("voyager.car?v9", Car.class);
			//Car benzSLS = car.accessControlPanel(Car.class.getName()+"?v9", Car.class);
			assertEquals("star.trek.voyager.module.benz.car_sls_amg.BenzSlsAmg-0.1.0.0",benzSLS.toString());
			Object engine = ObjectAccessor.Accessible.variable(benzSLS, "engine", null);
			assertEquals("star.trek.voyager.module.benz.engine_v9.EngineV9-0.1.0.0",engine.toString());
			
			//Engine check
			Object statusCheckerControlPanel = ObjectAccessor.Accessible.variable(engine, "statusChecker", null);
			Object statusChecker = ObjectAccessor.Accessible.variable(statusCheckerControlPanel,"wrapped",null);
			assertEquals("star.trek.voyager.module.pojo.status_checker.StatusChecker-0.1.0.0",statusChecker.toString());
			Object statusOutput = ObjectAccessor.Accessible.variable(engine, "statusOutput", null);
			assertEquals("star.trek.voyager.module.benz.car_sls_amg.BenzSlsAmg-0.1.0.0",statusOutput.toString());
			Object engineSocket = ObjectAccessor.Accessible.variable(engine, "engineSocket", null);
			assertEquals("star.trek.voyager.module.common.etasocket_common.CommonETASocket-0.1.0.0",engineSocket.toString());
			Object tempEngineSocket = ObjectAccessor.Accessible.variable(engine, "tempEngineSocket", null);
			assertNull(tempEngineSocket);
			
			//CommonETASocket check
			Object statusAbleModule = ObjectAccessor.Accessible.variable(engineSocket, "statusAbleModule", null);
			assertEquals("star.trek.voyager.module.benz.axletree_amg.AMGAxletree-0.1.0.0",statusAbleModule.toString());
			Object axletreeSocket = ObjectAccessor.Accessible.variable(engineSocket, "axletreeSocket", null);
			assertEquals("star.trek.voyager.module.benz.axletree_amg.AMGAxletree-0.1.0.0",axletreeSocket.toString());
			
			//AMGAxletree check
			Object[] wheels = ObjectAccessor.Accessible.variable(axletreeSocket, "wheels", null);
			int wheelNum = ObjectAccessor.Accessible.variable(axletreeSocket, "wheelNum", int.class);
			HashSet<Object> wheelSet = new HashSet<Object>();
			for(Object wheel:wheels){
				if(wheel!=null)wheelSet.add(wheel);
			}
			assertEquals(wheelNum,wheelSet.size());
			assertEquals(2,wheelNum);
		}
		
		{//ControlPanel car with enginev9 and two wheels
			ControlPanel benzSLSCP = car.accessControlPanel("voyager.car?v9", ControlPanel.class);
			Object benzSLS = ObjectAccessor.variable(benzSLSCP, "wrapped", null);
			//Car benzSLS = car.accessControlPanel(Car.class.getName()+"?v9", Car.class);
			assertEquals("star.trek.voyager.module.benz.car_sls_amg.BenzSlsAmg-0.1.0.0",benzSLS.toString());
			Object engine = ObjectAccessor.Accessible.variable(benzSLS, "engine", null);
			assertEquals("star.trek.voyager.module.benz.engine_v9.EngineV9-0.1.0.0",engine.toString());
			
			//Engine check
			Object statusCheckerControlPanel = ObjectAccessor.Accessible.variable(engine, "statusChecker", null);
			Object statusChecker = ObjectAccessor.Accessible.variable(statusCheckerControlPanel,"wrapped",null);
			assertEquals("star.trek.voyager.module.pojo.status_checker.StatusChecker-0.1.0.0",statusChecker.toString());
			Object statusOutput = ObjectAccessor.Accessible.variable(engine, "statusOutput", null);
			assertEquals("star.trek.voyager.module.benz.car_sls_amg.BenzSlsAmg-0.1.0.0",statusOutput.toString());
			Object engineSocket = ObjectAccessor.Accessible.variable(engine, "engineSocket", null);
			assertEquals("star.trek.voyager.module.common.etasocket_common.CommonETASocket-0.1.0.0",engineSocket.toString());
			Object tempEngineSocket = ObjectAccessor.Accessible.variable(engine, "tempEngineSocket", null);
			assertNull(tempEngineSocket);
			
			//CommonETASocket check
			Object statusAbleModule = ObjectAccessor.Accessible.variable(engineSocket, "statusAbleModule", null);
			assertEquals("star.trek.voyager.module.benz.axletree_amg.AMGAxletree-0.1.0.0",statusAbleModule.toString());
			Object axletreeSocket = ObjectAccessor.Accessible.variable(engineSocket, "axletreeSocket", null);
			assertEquals("star.trek.voyager.module.benz.axletree_amg.AMGAxletree-0.1.0.0",axletreeSocket.toString());
			
			//AMGAxletree check
			Object[] wheels = ObjectAccessor.Accessible.variable(axletreeSocket, "wheels", null);
			int wheelNum = ObjectAccessor.Accessible.variable(axletreeSocket, "wheelNum", int.class);
			HashSet<Object> wheelSet = new HashSet<Object>();
			for(Object wheel:wheels){
				if(wheel!=null)wheelSet.add(wheel);
			}
			assertEquals(wheelNum,wheelSet.size());
			assertEquals(2,wheelNum);
		}
		
		{//Java Interface test
			ModuleConsole ReferenceMap = CentralConsole.accessModuleConsole("agrael.collection.referencemap");
			Map<String,String> referenceMap = ReferenceMap.accessControlPanel(Map.class.getName(), null);
			assertNotNull(referenceMap);
		}
	}
	
	@Test public void test_JIOPi_0_4(){
		{
			ModuleConsole RedefineInterfaceModule = CentralConsole.accessModuleConsole("jiopi.ibean.testredefinemodule","0.1.0.0");
			RedefineInterface ri = RedefineInterfaceModule.accessControlPanel(RedefineInterface.class.getName(), RedefineInterface.class);
			assertEquals("classMethod in NewInterfaceAndClassControlPanelImpltrue",ri.getClassMethod());
			assertEquals("classStaticString",ri.getClassStaticString());
			assertEquals("redefineClassStaticString",ri.getRedefineClassStaticString());
			assertEquals("staticClassMethod in NewInterfaceAndClassControlPanelImpl",ri.getStaticClassMethod());
			Car myCar = ri.getCar();
			assertNotNull(myCar);
		}
	}
	
	
	@Test public void test_local_pool() throws SendMailException{
		ModuleConsole MailSender = CentralConsole.accessModuleConsole("jiopi.test.mailsender","0.1");
		//mailSender.operate("sendMail", void.class, "","","");
		{//common test
			MailSender ms = MailSender.accessControlPanel("jiopi.MailSender?test", MailSender.class);
			MailSender ms2 = MailSender.accessControlPanel("jiopi.MailSender?test", MailSender.class);
			assertSame(ms,ms2);
			assertEquals("smtp.yourmail.com",ms.getHostName());
			assertEquals("myname@yourmail.com",ms.getAuthenticationUserName());
			assertEquals("******",ms.getAuthenticationPassword());
			assertEquals("UTF-8",ms.getCharset());
			assertEquals("myname@yourmail.com",ms.getFrom());
		}
		
		{//method register test
			assertEquals("text smtp.default.com",MailSender.operate("sendMail", String.class, "","",""));
			assertEquals("html smtp.default.com",MailSender.operate("sendMail", String.class, "","","",""));
		}
		{
			Mail aMail = MailSender.accessControlPanel("jiopi.Mail", Mail.class);
			Mail bMail = MailSender.accessControlPanel(Mail.class.getName()+"?test", Mail.class);
			assertNotSame(aMail,bMail);
			assertEquals("MailImpl send with smtp.default.com",aMail.send());
			assertEquals("MailImpl send with smtp.yourmail.com",bMail.send());
		}
		
		{//redefine test
			assertEquals("text smtp.default.com",org.jiopi.ibean.sample.MyMailSender.sendMyMail("", "", ""));
			Mail mail = new org.jiopi.ibean.sample.MyMail();
			assertEquals("MailImpl send with smtp.yourmail.com",mail.send());
		}
	}
}
